﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Media.Imaging;
using AForge.Imaging;
using AForge.Imaging.Filters;
using BrainTechLLC;
using BrainTechLLC.ThreadSafeObjects;
using BrainTechLLC.ImageOperators;
using System.IO;
using System.Windows.Threading;
using System.Windows;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;

namespace ImageAppDataModels
{
    public class ResizeInfo
    {
        public object viewModel;
        public IFileImage f1;
        public int width;
        public int height;
        public bool done;
        public byte[] bytes;
        public string newFileName;
        public Timer tmr;
    }

    public class RotateInfo
    {
        public IFileImage f1;
        public Rotation rotation;
        public bool clockwise;
    }

    public class FileNameAndBytes
    {
        public byte[] bytes;
        public string fileName;
        public int tries;
        public IFileImage fileImage;
        public ResizeInfo info;
        public bool entered;
    }

    public static class FileImageRotationIFileImage
    {
        public static void LoadImageData(FileImage fileImage)
        {
            fileImage.Load();
        }

        public static Bitmap BeginRotate(this IFileImage f1, Rotation rotation, bool clockwise)
        {
            ParameterizedThreadStart ts = new ParameterizedThreadStart(RotateWorker);
            Thread t = new Thread(ts);
            t.Start(new RotateInfo() { f1 = f1, rotation = rotation, clockwise = clockwise });
            t.Name = "BeginRotate";
            t.IsBackground = true;
            t.Priority = ThreadPriority.BelowNormal;
            return null;
        }

        private static void RotateWorker(object o)
        {
            RotateInfo info = o as RotateInfo;
            Rotate(info.f1, info.rotation, info.clockwise);
            FileImage fi = info.f1 as FileImage;
            fi.Thumbnail = null;
            fi.ImageSource = null;
            fi.ClearImageInfo();
            fi.RaisePropertyChangedUIThread("ThumbnailRotate");
        }

        public static Bitmap Rotate(this IFileImage f1, Rotation rotation, bool clockwise)
        {
            RotateFlipType rotationType = rotation.GetRotateFlipType(clockwise);
            Bitmap bm1 = System.Drawing.Image.FromFile(f1.FileName) as Bitmap;

            if (rotationType != RotateFlipType.RotateNoneFlipNone)
            {
                bm1 = FileImageRotation.Rotate(bm1, rotation, f1.FileName, clockwise, Settings.Values.ResizeJpegQuality);
                f1.Bitmap = bm1;
            }

            return bm1;
        }

        public static string GetNewResizeFileName(string originalFileName)
        {            
            if (string.IsNullOrEmpty(Settings.Values.ResizedFileName))
            {
                return originalFileName;
            }

            string newFileNameOnly = Path.GetFileName(originalFileName).Replace(Path.GetExtension(originalFileName), string.Empty);

            return Path.GetDirectoryName(originalFileName) + @"\" +
                    Settings.Values.ResizedFileName
                    .Replace("{0}", newFileNameOnly)
                    .Replace("*", newFileNameOnly);
        }

        public static Bitmap BeginResize(this IFileImage f1, int width, int height)
        {
            ParameterizedThreadStart ts = new ParameterizedThreadStart(ResizeWorker);
            Thread t = new Thread(ts);
            t.Start(new ResizeInfo() { f1 = f1, width = width, height = height, done = false });
            t.Name = "BeginResize";
            t.IsBackground = true;
            t.Priority = ThreadPriority.BelowNormal;
            return null;
        }

        private static void ResizeWorker(object o)
        {
            ResizeInfo info = o as ResizeInfo;
            Resize(info.f1, info.width, info.height, info);

            while (!info.done)
            {
                Thread.Sleep(100);
            }
        }

        public static string Resize(this IFileImage f1, int width, int height, ResizeInfo info)
        {
            try
            {
                // Load from disk
                byte[] origBytes = f1.DataProvider.ReadAllImageBytes(f1.FileName);
                Bitmap bm1 = System.Drawing.Image.FromStream(new MemoryStream(origBytes), true, false) as Bitmap;

                if (bm1 == null)
                    return f1.FileName;

                byte[] bytes = null;

                if ((width < height && f1.OriginalBitmapWidth > f1.OriginalBitmapHeight) ||
                    (width > height && f1.OriginalBitmapWidth < f1.OriginalBitmapHeight))
                {
                    int tempHeight = height;
                    height = width;
                    width = tempHeight;
                }

                double scaleFactor = Scaling.GetScaledImageDimensions((double)f1.OriginalBitmapWidth, (double)f1.OriginalBitmapHeight, (double)width, (double)height);
                width = (int)((double)f1.OriginalBitmapWidth * scaleFactor);
                height = (int)((double)f1.OriginalBitmapHeight * scaleFactor);

                // Perform the resize (force high quality resizing)
                // Optimize
                var renderSettings = new RenderSettings()
                {
                    PixelFormat = bm1.PixelFormat,
                    Interpolation = Settings.Values.InterpolationMode,
                    Smoothing = Settings.Values.SmoothingMode,
                    RenderingMethod = InternalRenderingMethod.None,
                    ForceHighQuality = true
                };

                Bitmap bmResized = bm1.CreateBitmap(width, height, renderSettings);

                for (int n = 0; n < bm1.PropertyItems.Length; n++)
                {
                    bmResized.SetPropertyItem(bm1.PropertyItems[n]);
                }

                string newFileName;
                (f1 as FileImage)._oldName = f1.FileName;

                if (width == f1.OriginalBitmapWidth && height == f1.OriginalBitmapHeight)
                {
                    newFileName = f1.FileName;
                }
                else
                {
                    newFileName = GetNewResizeFileName(f1.FileName);
                }

                if (info != null)
                {
                    info.newFileName = newFileName;
                }

                ImageCodecInfo jpegCodec;
                EncoderParameters jpegParams;

                int jpegQuality = Settings.Values.ResizeJpegQuality;

                if (jpegQuality < 5 || jpegQuality > 100)
                {
                    jpegQuality = 80;
                }

                JpegEncoding.GetJPEGParamsForConversionQuality(jpegQuality, out jpegCodec, out jpegParams);

                try
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        bmResized.Save(ms, jpegCodec, jpegParams);
                        bytes = ms.ToArray();
                        if (info != null)
                        {
                            info.bytes = bytes;
                        }
                        else
                        {
                            f1.DataProvider.WriteAllBytes(newFileName, bytes);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }

                if (bytes != null)
                {
                    (f1 as FileImage).OnRotateOrResizeDone(info);
                }

                return newFileName;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return string.Empty;
            }
        }


    }
}
